#pragma once
/**@note glad, include glad *before* QOpenGL-Related-Header*/
#include "../../GLState.h"
#include <mutex>
#include <QOpenGLContext>
#include <QQuickView>
#include <QQuickWindow>
#include <QQuickItem>
#include <QOffscreenSurface>
#include <QSGSimpleTextureNode>
#include <QThread>

/***************************** ThreadRenderer *************************************************/
class QRenderThread;
class QRenderer : public QQuickItem {
	Q_OBJECT
public:
	QRenderer();

	static void setItemVisible(bool visible);
   
protected:
	QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;

	void keyPressEvent(QKeyEvent *event) override;
	void keyReleaseEvent(QKeyEvent *event) override;

private:
	QRenderThread *m_renderThread = nullptr;

	static QRenderer* sInstance;

	void captureWindow();
};

/************** Qt specified proc loader ***********/
class QtGLProcLoader : public IGLProcLoader {
private:
	QOpenGLContext* context;
public:
	explicit QtGLProcLoader(QOpenGLContext* context) : context(context) {}
	void* getProcAddress(const char* name) const override { return reinterpret_cast<void*>(context->getProcAddress(name)); }
};

/***************************** RenderThread *************************************************/
/*
 * The render thread shares a context with the scene graph and will render into two separate FBOs,
 * one to use for display and one to use for rendering.
 */
class QRenderThread : public QThread {
	Q_OBJECT
public:
	QRenderThread() = default;

	QOffscreenSurface *offscreenSurface = nullptr;
	QOpenGLContext *glContext = nullptr;

public slots:
	void renderNext();
	void shutdown();

signals:
	void textureReady(int texture);
};

/***************************** TextureNode *************************************************/
class QTextureNode : public QObject, public QSGSimpleTextureNode {
	Q_OBJECT
public:
	QTextureNode(QQuickWindow *window);
	~QTextureNode() override;

signals:
	void textureInUse();
	void pendingNewTexture();

public slots:
	// Before the scene graph starts to render, we update to the pending texture
	void prepareNode();
	// This function gets called on the FBO rendering thread and will store the texture id and size and schedule an update on the window.
	void newTexture(int texture);

private:
	int m_texture;

	QSGTexture *m_osgTexture;
	QQuickWindow *m_window;

	std::mutex m_mutex;

	int m_frameCnt = 0;
	int m_frameTotMs = 0;
};